package com.test;

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName: FfmpegUtils
 * @Description: ffmepeg工具类
 * @Author: wzb
 * @Date: 2021/4/20 9:55
 */
@Slf4j
public class FfmpegUtils {
//    public static final String FFMPEG_PATH = "/usr/local/ffmpeg/ffmpeg-git-20210405-amd64-static/ffmpeg";
//    public static final String FILE_PATH = "/usr/local/ffmpeg/ffmpeg-git-20210405-amd64-static/test/";
    public static final String FFMPEG_PATH = "E:\\software\\ffmpeg\\bin\\ffmpeg.exe";
    public static final String FILE_PATH = "C:\\Users\\91941\\Desktop\\cc\\";
    public static final String SUFFIX_MP4 = ".mp4";
    public static final String SUFFIX_IMG = ".jpg";

    public static void convertImg(String prepareName) {
        String name = prepareName.split("\\.")[0] + SUFFIX_IMG;
        long start = System.currentTimeMillis();
        videoCatchImg(FILE_PATH + prepareName, FILE_PATH + name);
        long end = System.currentTimeMillis();
        log.info("convert Img 耗时:{}", (end - start));
    }

    public static void convertCode(String prepareName) {
        String name = prepareName.split("\\.")[0] + SUFFIX_MP4;
        long start = System.currentTimeMillis();
        executeCodecs(FILE_PATH + prepareName, FILE_PATH + name);
        long end = System.currentTimeMillis();
        log.info("convertCode 耗时:{}", (end - start));
    }

    public static void getVideoTime11(String prepareName) {
        getVideoTime(FILE_PATH + prepareName);
    }

    /**
     * @param uploadPath 用于指定要转换格式的文件,要截图的视频源文件
     * @param targetPath 格式转换后的的文件保存路径
     * @Date: 2021/4/20
     * @Description:视频转码 ffmpeg能解析的格式：（asx，asf，mpg，wmv，3gp，mp4，mov，avi，flv等）
     */
    public static boolean executeCodecs(String uploadPath, String targetPath) {
        if (!check(uploadPath)) {
            return false;
        }
        // 创建一个List集合来保存转换视频文件为flv格式的命令
        List<String> commands = new ArrayList<>();
        // 添加转换工具路径
        commands.add(FFMPEG_PATH);
        // 添加参数＂-i＂，该参数指定要转换的文件
        commands.add("-i");
        // 添加要转换格式的视频文件的路径
        commands.add(uploadPath);
        //指定转换的质量
        commands.add("-qscale");
        commands.add("1");
        //设置音频码率
        commands.add("-ab");
        commands.add("64");
        //设置声道数
        commands.add("-ac");
        commands.add("2");
        //设置声音的采样频率
        commands.add("-ar");
        commands.add("22050");
        //设置帧频
        commands.add("-r");
        commands.add("30");
        // 添加参数＂-y＂，该参数指定将覆盖已存在的文件
        commands.add("-y");
        commands.add(targetPath);
        return doCmd(commands);
    }


    /**
     * @param uploadPath 用于指定要转换格式的文件,要截图的视频源文件
     * @param targetPath 格式转换后的的文件保存路径
     * @Date: 2021/4/20
     * @Description:截取视频图片
     */
    public static boolean videoCatchImg(String uploadPath, String targetPath) {
        if (!check(uploadPath)) {
            return false;
        }
        List<String> commands = new java.util.ArrayList<>();
        commands.add(FFMPEG_PATH);
        //输入文件
        commands.add("-i");
        commands.add(uploadPath);
        //输出文件若存在可以覆盖
        commands.add("-y");
        //指定图片编码格式
        commands.add("-f");
        commands.add("image2");
        commands.add("-q:v");
        commands.add("1");
        //设置截取视频第0秒时的画面
        commands.add("-ss");
        commands.add("0");
        //设置截图大小
        commands.add("-s");
        commands.add("460x750");
        //截取的图片路径
        commands.add(targetPath);

        return doCmd(commands);
    }

    /**
     * @Method: getVideoTime
     * @Param: [uploadPath]
     * @return: com.test.VideoInfo
     * @Author: wzb
     * @Date: 2021/4/23
     * @Description: 获取视频信息
     */
    public static VideoInfo getVideoTime(String uploadPath) {
        VideoInfo videoInfo = new VideoInfo();
        if (!check(uploadPath)) {
            return videoInfo;
        }
        List<String> commands = new ArrayList<>();
        commands.add(FFMPEG_PATH);
        commands.add("-i");
        commands.add(uploadPath);
        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commands);
            Process p = builder.start();

            //从输入流中读取视频信息
            BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            StringBuilder stringBuilder = new StringBuilder();
            String line = "";
            while ((line = br.readLine()) != null) {
                stringBuilder.append(line);
            }
            br.close();

            //从视频信息中解析时长
            String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s";
            Pattern pattern = Pattern.compile(regexDuration);
            Matcher m = pattern.matcher(stringBuilder.toString());
            if (m.find()) {
                int time = getTimelen(m.group(1));
                log.debug("视频时长：" + time + "s , 开始时间：" + m.group(2) + ", 比特率：" + m.group(3) + "kb/s");
                videoInfo.duration(time).startTime(m.group(2)).bitRate(m.group(3));
            }

            String regexVideo = "Video: (.*?), (.*?), (.*?)[,\\s]";
            pattern = Pattern.compile(regexVideo);
            m = pattern.matcher(stringBuilder.toString());
            if (m.find()) {
                log.debug("编码格式：" + m.group(1) + ", 视频格式：" + m.group(2) + ", 分辨率：" + m.group(3) + "kb/s");
                videoInfo.codingFormat(m.group(1)).format(m.group(2)).resolvingPower(m.group(3));
            }
            log.info(videoInfo.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return videoInfo;
    }

    private static int getTimelen(String timelen) {
        int min = 0;
        String strs[] = timelen.split(":");
        if (strs[0].compareTo("0") > 0) {
            // 秒
            min += Integer.valueOf(strs[0]) * 60 * 60;
        }
        if (strs[1].compareTo("0") > 0) {
            min += Integer.valueOf(strs[1]) * 60;
        }
        if (strs[2].compareTo("0") > 0) {
            min += Math.round(Float.valueOf(strs[2]));
        }
        return min;
    }

    public static boolean doCmd(List<String> commands) {
        log.info("execute commands:{}", commands);
        boolean mark = true;
        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commands);
            builder.redirectErrorStream(true);
            builder.start();
        } catch (Exception e) {
            mark = false;
            log.info("ffmpeg execute cmd error:{}", e.getMessage());
            e.printStackTrace();
        }
        return mark;
    }

    public static boolean check(String uploadPath) {
        File file = new File(uploadPath);
        if (!file.exists()) {
            log.info("路径[{}]对应的视频文件不存在!", uploadPath);
            return false;
        }
        return true;
    }
}